#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <gmp.h>
#include <time.h>

#define SIZE_4 1
#define WORDS_4_BITS 8

#define NAILS 4
#define RAND_MOD 2048
#define RAND_THRESHOLD 511
#define BASE 2
#define ORDER 1
#define ENDIAN 0

extern Product4 (void *a, void *b, void *c, unsigned int *sa, unsigned int *sb, unsigned int *sc);

int main(int argc, char **argv) {

    mpz_t x; mpz_init(x);
    mpz_t y; mpz_init(y);

    int number_of_bits = 3200;
    int number_of_tests = 100;
    int i,j;
    double time_elasped = 0.0;

    if(argc >=2){
	number_of_bits = atoi(argv[1]);
	number_of_tests = atoi(argv[2]);
    }

    clock_t start, finish;
    int num_correct = 0, num_wrong = 0;

    char *x_str = (char *) malloc((1 + number_of_bits)*sizeof(char)); 
    char *y_str = (char *) malloc((1 + number_of_bits)*sizeof(char)); 
    srand ( time(NULL));

    start = clock();
    for(j = 0; j < number_of_tests; j++){

	for(i = 0; i < number_of_bits; i++){
	    x_str[i] = ((rand()%RAND_MOD) > RAND_THRESHOLD) ? '1' : '0';
	}
	x_str[number_of_bits] = '\0';

	for(i = 0; i < number_of_bits; i++){
	    y_str[i] = ((rand()%RAND_MOD) > RAND_THRESHOLD) ? '1' : '0';
	}
	y_str[number_of_bits] = '\0';

	mpz_set_str(x, x_str, BASE); mpz_set_str(y, y_str, BASE);

	void *x_address;
	void *y_address;
	size_t *x_size = malloc(sizeof(size_t));
	size_t *y_size = malloc(sizeof(size_t));
	size_t *z_size = malloc(sizeof(size_t));

	x_address = mpz_export(NULL, x_size, ORDER, SIZE_4, ENDIAN, NAILS, x);
	y_address = mpz_export(NULL, y_size, ORDER, SIZE_4, ENDIAN, NAILS, y);

	void *z_address = malloc((*x_size + *y_size)*WORDS_4_BITS);

	Product4(x_address, y_address, z_address, x_size, y_size, z_size);

	mpz_t z;
	mpz_init(z);

	mpz_import(z, *z_size, ORDER, SIZE_4, ENDIAN, NAILS, z_address);

	mpz_t result;
	mpz_init(result);
	mpz_mul(result,x,y);

	if(mpz_cmp(result,z) == 0)
	    num_correct ++;
	else
	    num_wrong ++;
    }

    finish = clock();
    printf("============================================================\n");
    printf("\n\n");
    printf("Number of bits per number: %d\n", number_of_bits);
    printf("Number of multiplications done: %d\n", number_of_tests);
    printf("Number of correct multiplication: %d\n", num_correct);
    printf("Number of wrong multiplication: %d\n", num_wrong);
    printf("Total time elapsed:  %lf seconds", ((double) (finish - start))/CLOCKS_PER_SEC);
    printf("\n\n");
    printf("============================================================\n");
    return 0;
}
